package kr.co.bettersoftportal.site.management.service;

import kr.co.bettersoftportal.site.domain.*;
import kr.co.bettersoftportal.site.management.dao.*;

import kr.co.bettersoftportal.site.management.util.BettersoftPortalCommon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.MailException;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.web.multipart.MultipartFile;


import javax.imageio.ImageIO;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.List;
import java.util.UUID;


public class BettersoftPortalServiceImpl implements BettersoftPortalService {


    // SLF4J Logging
    private Logger logger = LoggerFactory.getLogger(BettersoftPortalServiceImpl.class);

    @Autowired
    private MemberDao memberDao = null;

    @Autowired
    private JavaMailSender mailSender = null;

    public String getName(String name) {
        String rtnName = "";
        return (new StringBuilder()).append(name).append(rtnName).toString();
    }

    public Member getMemberById(String id) {
        return memberDao.getMemberById(id);
    }

    public String getMemberExistById(String id) {
        return memberDao.getMemberExistById(id);
    }

    public String logIn(String id, String password) {
        String result = "";
        memberDao.getMemberExistById(id);
        if(("0").equals(memberDao.getMemberExistById(id))) {
            result = "NON_EXIST";
        } else {
            result = "EXIST";
        }
        if(("EXIST").equals(result)) {
            Member member = new Member();

            member.setBETTERSOFT_ID(id);

            BettersoftPortalCommon common = new BettersoftPortalCommon();
            member.setPASSWORD(common.getEncodedPassword(password));

            logger.info("logIn Service id : {}", member.getBETTERSOFT_ID());
            logger.info("logIn Service password : {}", member.getPASSWORD());


            if(Integer.parseInt((String)memberDao.logIn(member)) > 0) {
                logger.info("logIn SUCCESS");
                return "SUCCESS";
            } else {
                logger.info("logIn FALSE");
                return "FALSE";
            }
        }

        return result;
    }

    public String insertMember(Member member){
        return memberDao.insertMember(member);
    }

    /**
     * MimeMessage 를 이용하는 MimeMessageHelper 를 이용해 메일 보내기
     *
     * @param subject
     * @param content
     * @param fromUser
     * @param toUser
     * @param userId
     */
    public String sendMail(String subject, String content, String fromUser, String toUser, String userId){

        MimeMessage message = mailSender.createMimeMessage();

        try{
            /**
             * messageHelper 에 들어갈 MimeMessage message, 첨부파일여부, 인코딩
             */

            MimeMessageHelper messageHelper = new MimeMessageHelper(message, false, "UTF-8");

            messageHelper.setSubject(subject); // 제목 셋팅
            messageHelper.setText(content, true); // 내용 셋팅
            messageHelper.setFrom(new InternetAddress(fromUser, "Bettersoft webmaster")); // 보낸사람 셋팅
            messageHelper.setTo(new InternetAddress(toUser, userId, "UTF-8")); // 받는 사람

            //DataSource dataSource = new FileDataSource()

            //messageHelper.addAttachment();

        }catch (Throwable e){

            return "메일 전송에 실패했습니다.";

        }
        try{
            mailSender.send(message);
            return "메일이 성공적으로 전송되었습니다.";

        }catch (MailException e){

            return "메일 전송에 실패했습니다.";

        }
    }


    /**
     * 멤버 정보를 이용하여 비밀번호 수정
     *
     * @param member
     * @return
     */
    public String updatePasswordByMember(Member member){
        return memberDao.updatePasswordByMember(member);
    }


    /**
     * 파일 업로드 서비스
     *
     * 전송되어 온 MultipartFile 을 그대로 서버에 업로드 한다.
     * UUID 를 이용하여 유니크한 이름을 생성하여 업로드 한다.
     * 다운로드 기능을 구현했을시에 업로드시의 파일 이름을 재현하기 위해 파일의 원래 이름을 기록하여 둔다.
     *
     * @param file
     * @param realPath
     * @return
     */
    public UploadFile uploadFile(MultipartFile file, String realPath){

        InputStream stream; // Input Stream 생성

        /**
         * 파일의 확장자 명을 추출한다.
         */
        logger.info("file Name : {}", file.getOriginalFilename());
        String fileName = file.getOriginalFilename();

        /**
         * 기존 파일이름에서 마지막 3글자를 추출한다.
         */
        String fileSuffix = fileName.substring(fileName.length()-3, fileName.length());
        logger.info("file Suffix : {}", fileSuffix);

        UUID uuid = UUID.randomUUID(); // 랜덤 UUID 이름 생성
        String tempFileName = uuid.toString() + "." + fileSuffix; // 임시 파일 이름 저장 기존의 확장자명을 덧붙인다.

        try {
            stream = file.getInputStream();

            OutputStream bos = new FileOutputStream(realPath + tempFileName);
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = stream.read(buffer, 0, 8192)) != -1) {
                bos.write(buffer, 0, bytesRead);
            }
            bos.close();
            stream.close();

            // 파일 쓰고 stream 닫기

            /*
            if (logger.isDebugEnabled()) {
                logger.debug("The file has been written to \"" + realPath
                        + tempFileName);
            }
            */

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        UploadFile boardFile = new UploadFile();

        boardFile.setFileName(file.getOriginalFilename());
        boardFile.setFileSize(Long.toString(file.getSize()));
        boardFile.setContentType(file.getContentType());
        boardFile.setTempFileName(tempFileName);

        return boardFile;

    }


    /**
     * 비율 고정 이미지 만들기
     *
     * 전달되어 진 width, height 를 토대로 고정비율을 가진 이미지를 생성하여 업로드 한다.
     * width, height 의 길이를 비교하여 긴쪽은 유지하고 짧은쪽은 비율에 맞게 재조정된다.
     * 남은 부분은 RGB 값을 지정하여 채워넣는다.
     *
     * @param src
     * @param dest
     * @param width
     * @param height
     * @return
     * @throws IOException
     */
    public String createPushImage(File src, File dest, int width, int height) throws IOException{

        // 320 X 240

        // 결과물의 가로, 세로.
        int destWidth = width;
        int destHeight = height;

        // 결과물의 가로 : 세로 비율    --> 원본의 가로 세로 비율과 비교해야 함.
        float destWHRatio =  ((float)destWidth/(float)destHeight);

        // 원본의 가로, 세로
        int orgWidth =0;
        int orgHeight = 0;

        // 원본의 가로 : 세로 비율 --> 결과물의 가로 세로 비율과 비교해야함.
        float orgWHRatio = 0;

        // 확대,축소 비율
        float resizeRatio = 0;

        // 결과물의 가로, 세로
        int resultWidth = 0;
        int resultHeight = 0;
        float resultWHRatio = 0;

        try{
            // 원본 파일
            BufferedImage originalImage = ImageIO.read(src);		// 원본 파일명
            orgWidth = originalImage.getWidth();
            orgHeight = originalImage.getHeight();
            orgWHRatio = (float)orgWidth/(float)orgHeight;
//            System.out.println("destWidth:"+destWidth+"//destHeight:"+destHeight+"//destWHRatio:"+destWHRatio);
//            System.out.println("orgWidth:"+orgWidth+"//orgHeight:"+orgHeight+"//orgWHRatio:"+orgWHRatio);

            if(destWHRatio<orgWHRatio){		// 원본보다 가로 비율이 클 경우 가로를 기준으로 잡는다.
                resizeRatio = (float) destWidth/ (float)orgWidth;
//                System.out.println("가로 기준");
            }else{										// 원본보다 세로 비율이 클 경우 세로를 기준으로 잡는다.
                resizeRatio = (float)destHeight / (float)orgHeight;
//                System.out.println("세로 기준");
            }

            // 결과물 사이즈 지정.
            resultWidth = (int) (orgWidth * resizeRatio);
            resultHeight = (int) (orgHeight * resizeRatio);
//            System.out.println("resizeRatio:"+resizeRatio+"//resultWidth:"+resultWidth+"//resultHeight:"+resultHeight);
            resultWHRatio = (float)resultWidth /(float) resultHeight;
//            System.out.println("orgWHRatio:"+orgWHRatio+"//resultWHRatio:"+resultWHRatio);
            int type = originalImage.getType() == 0? BufferedImage.TYPE_INT_ARGB : originalImage.getType();


            // 결과물 생성. --> 사이즈를 넣는다.

            // 저장할 파일명. png 타입. jpg보다 선명함.
            BufferedImage resizeImagePng = resizeImage(originalImage, type, resultWidth, resultHeight);
//			ImageIO.write(resizeImagePng, "png", new File("d:\\imgs\\c1-1.png"));
//
//			// 저장할 파일명. jpg 타입
//			BufferedImage resizeImageJpg = resizeImage(originalImage, type);
//			ImageIO.write(resizeImageJpg, "jpg", new File("d:\\imgs\\aa1.jpg")); 	// 저장할 파일명
//
//			// 힌트 사용. 큰 차이 못느낌
//			BufferedImage resizeImageHintJpg = resizeImageWithHint(originalImage, type);
//			ImageIO.write(resizeImageHintJpg, "jpg", new File("d:\\imgs\\aa3.jpg"));
//			// 힌트 사용.
//			BufferedImage resizeImageHintPng = resizeImageWithHint(originalImage, type);
//			ImageIO.write(resizeImageHintPng, "png", new File("d:\\imgs\\aa4.png"));



            // 하나의 이미지를 새로운 이미지(크기 고정)의 중앙에 위치하고 남은 공간은 흑백 처리하도록 한다.
            // 리사이즈 과정은 거쳤다고 치고. 전체 틀을 넘어가는 경우는 없다고 치자.
            BufferedImage image1 = resizeImagePng;
//			BufferedImage image2 = ImageIO.read(new File("d:\\imgs\\aa2.png"));

//			int width = Math.max(image1.getWidth(), image2.getWidth());
//			int height = image1.getHeight() + image2.getHeight();

            // 시작점
            int drawWidthPoint = 0;
            int drawHeightPoint = 0;



            BufferedImage mergedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            Graphics2D graphics = (Graphics2D) mergedImage.getGraphics();

            // 배경이 될 부분에 들어갈 색깔 지정
            Color bgColor = new Color(255, 255, 255);

            // 배경 색칠. - 검은색
//            graphics.setBackground(bgColor);

            // 시작점 위치 잡기.
            // 예를 들어 틀이 1000,1000이고 이미지가 400,300이라면 시작점 = 600,700이 검은 화면이 되고.
            // 300이 시작점이 됨. 350이 시작점이 됨.
            if(width!=image1.getWidth()){
                drawWidthPoint = (width - image1.getWidth())/2; 				//
            }
            if(height!=image1.getHeight()){
                drawHeightPoint = (height - image1.getHeight())/2;
            }
            graphics.drawImage(image1, drawWidthPoint, drawHeightPoint, bgColor, null);		// 0,0 -> 시작점. 에 그린다. 를 원하지 않는다.
//			graphics.drawImage(image2, 0, image1.getHeight(), null);

            ImageIO.write(mergedImage, "png", dest);
            // ImageIO.write(mergedImage, "jpg", new File("c:\\mergedImage.jpg"));
            // ImageIO.write(mergedImage, "png", new File("c:\\mergedImage.png"));



        } catch (IOException ioe) {
            ioe.printStackTrace();
        }

//        System.out.println("작업이 완료되었습니다");

        return dest.getName();

    }

    /**
     * 고정 비율로 이미지 리사이즈 하기, 이미지 비율 유지
     *
     * @param originalImage
     * @param type
     * @param resultWidth
     * @param resultHeight
     * @return
     */
    private static BufferedImage resizeImage(BufferedImage originalImage, int type, int resultWidth, int resultHeight){
        BufferedImage resizedImage = new BufferedImage(resultWidth, resultHeight, type);
        Graphics2D g = resizedImage.createGraphics();
//		g.drawImage(originalImage, 0, 0, IMG_WIDTH, IMG_HEIGHT, null);		// 그냥 자름
        g.drawImage(originalImage, 0, 0, resultWidth, resultHeight, null);		// 리사이즈
        g.dispose();

        return resizedImage;
    }


    /**
     * 브라우저에서 password SHA 암호화 dwr용
     * @param password
     * @return
     */
    public String passwordEncoding(String password){
        BettersoftPortalCommon common = new BettersoftPortalCommon();
        return common.getEncodedPassword(password);
    }


    /**
     * 검색 단어로 회원 조회하기.
     *
     * @param member
     * @return
     */
    public List getMemberListBySearchword(Member member){
        return memberDao.getMemberListBySearchword(member);
    }


    /**
     * 검색 단어로 회원 수 조회하기.
     *
     * @param member
     * @return
     */
    public String getTotalMemberCountBySearchword(Member member){
        return memberDao.getTotalMemberCountBySearchword(member);
    }

    /**
     * ID 로 멤버 정보 업데이트
     *
     * @param member
     * @return
     */
    public String updateMemberByBettersoftId(Member member){
        return memberDao.updateMemberByBettersoftId(member);
    }


}
